package com.strongbj.iot.devices.dam.message;

import com.strongbj.core.util.ByteUtil;

public class DAMMessageFactory {
	private final static int FRAME_MAX_SIZE=1000;// 一帧的最大尺寸
	private final static int STATIC_DATA_SIZE=27;// 静态数据的长度（除数据段外的消息长度）
	private final static int SN_SIZE=8;			// 流水号长度
	private final static short HEADER1=0xAA;	// 协议头
	private final static short HEADER2=0x55;	// 协议头
	private final static byte[] END_FLAG = {0x0D,0x0A,0x55,0x0D,0x0A};	// 结束符
	public byte[] createDAMMessage(
			 byte[] sn,
			 byte[] deviceCode,
			 byte deviceType, 
			 byte version,
			 byte command,
			 byte[] datas
	    ) {
			int dataLen = datas.length;		// 数据长度
			byte totalFrame=Integer.valueOf(((int)Math.floor((double)dataLen/(double)FRAME_MAX_SIZE))+1).byteValue(); // 计算需要发送多少帧数据
			byte[] result = new byte[STATIC_DATA_SIZE*totalFrame+dataLen];		 // 开辟需要发送的数据长度
			byte[] devCode = deviceCode;          	 // 将设备编码转为字节数组
			for(byte i=1;i<=totalFrame;i++) {
				
				setCurrentFrameDatas(result,sn,devCode,deviceType,version,command,totalFrame,i,datas);
			}
			return result;
	    }
	
	public byte[] createDAMMessage(
			 byte[] sn,
			 String deviceCode,
			 byte deviceType, 
			 byte version,
			 byte command,
			 byte[] datas
	    ) {
			return this.createDAMMessage(sn,getDeviceCodeFromString(deviceCode),deviceType,version,command,datas);
	    }
	
	/**
	 * 获取设备编码
	 * @param deviceCode 字符型的设备编码
	 * @return			 返回byte数组的设备编码
	 */
	private byte[] getDeviceCodeFromString(String deviceCode) {
		return ByteUtil.hexStringToBytes(deviceCode);          // 将设备编码转为字节数组
	}
	
	/**
	 * 设置当前帧的数据到指定数组中
	 * @param destDatas		目标数据数组
	 * @param deviceCode	设备编码
	 * @param deviceType	设备类型
	 * @param version		设备版本号
	 * @param command		命令
	 * @param totalFrame	总帧数
	 * @param currentFrame	当前帧
	 * @param srcDatas		源数据数组
	 */
	private void setCurrentFrameDatas(
			byte[] destDatas,
			byte[] sn,
			 byte[] deviceCode,
			 byte deviceType, 
			 byte version,
			 byte command,
			 byte totalFrame,
			 byte currentFrame,
			 byte[] srcDatas) {
					int destDatasOffset=(currentFrame-1)*(STATIC_DATA_SIZE+FRAME_MAX_SIZE);  // 计算目标数据的偏移量
					int srcDatasOffset=(currentFrame-1)*FRAME_MAX_SIZE;						 // 计算源数据的偏移量
					// 设置协议头
					destDatas[destDatasOffset]=(byte)HEADER1;
					destDatas[destDatasOffset+1]=(byte)HEADER2;
					
					if(sn.length!=SN_SIZE) throw new RuntimeException("协议SN段尺寸不等于"+SN_SIZE+"位");
					
					System.arraycopy(sn, 0, destDatas, destDatasOffset+2, SN_SIZE);
					// 设置长度 2byte
					int dataLen=Math.min(srcDatas.length-srcDatasOffset,FRAME_MAX_SIZE); // 取当前帧的数据段长度
					byte[] bLen = ByteUtil.shortToByteArr((short)(10+SN_SIZE+dataLen));
					System.arraycopy(bLen, 0, destDatas, destDatasOffset+2+SN_SIZE, bLen.length);
					// 设置设备编号 3byte
					System.arraycopy(deviceCode, 0,  destDatas, destDatasOffset+4+SN_SIZE, 3);
					// 设置设备类型
					destDatas[destDatasOffset+7+SN_SIZE]=deviceType;
					// 设置版本号
					destDatas[destDatasOffset+8+SN_SIZE]=version;
					// 设置命令
					destDatas[destDatasOffset+9+SN_SIZE]=command;
					// 设置总帧数
					destDatas[destDatasOffset+10+SN_SIZE]=totalFrame;
					// 设置当前帧数
					destDatas[destDatasOffset+11+SN_SIZE]=currentFrame;
					// 设置数据段
					System.arraycopy(srcDatas, srcDatasOffset, destDatas, destDatasOffset+12+SN_SIZE, dataLen);
					// 设置校验码
					byte nor=0;
					// NOR：从长度字节到数据的异或校验
					int norEndPoint = destDatasOffset+STATIC_DATA_SIZE+dataLen-2-END_FLAG.length;
					for(int i=destDatasOffset+SN_SIZE+4;i < norEndPoint;i++) {
						nor^=destDatas[i];
					}
					destDatas[destDatasOffset+STATIC_DATA_SIZE+dataLen-2-END_FLAG.length]=nor;
					// 设置结束标记
					System.arraycopy(END_FLAG, 0, destDatas, STATIC_DATA_SIZE+dataLen-END_FLAG.length, END_FLAG.length);
	}
}
